home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / src / login.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-10  |  13.3 KB  |  543 lines

  1. /* @(#) $Header: login.c,v 1.15 91/10/08 12:54:38 deyke Exp $ */
  2.  
  3. #include <sys/types.h>
  4.  
  5. #include <stdio.h>      /* must be before pwd.h */
  6.  
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <pwd.h>
  11. #include <signal.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/ptyio.h>
  15. #include <sys/rtprio.h>
  16. #include <sys/stat.h>
  17. #include <termio.h>
  18. #include <time.h>
  19. #include <unistd.h>
  20. #include <utmp.h>
  21.  
  22. #include "global.h"
  23. #include "mbuf.h"
  24. #include "timer.h"
  25. #include "hpux.h"
  26. #include "telnet.h"
  27. #include "login.h"
  28.  
  29. extern struct utmp *getutent();
  30. extern struct utmp *getutid();
  31. extern void endutent();
  32. extern void pututline();
  33.  
  34. #define MASTERPREFIX        "/dev/pty"
  35. #define SLAVEPREFIX         "/dev/tty"
  36.  
  37. #define PASSWDFILE          "/etc/passwd"
  38. #define PWLOCKFILE          "/etc/ptmp"
  39.  
  40. #define DEFAULTUSER         "guest"
  41. #define FIRSTUID            400
  42. #define MAXUID              4095
  43. #define GID                 400
  44. #define HOMEDIRPARENTPARENT "/users/funk"
  45.  
  46. /* login server control block */
  47.  
  48. struct login_cb {
  49.   int  pty;                     /* pty file descriptor */
  50.   int  num;                     /* pty number */
  51.   char  id[4];                  /* pty id (last 2 chars) */
  52.   int  pid;                     /* process id of login process */
  53.   char  inpbuf[512];            /* pty read buffer */
  54.   char  *inpptr;                /* pty read buffer pointer */
  55.   int  inpcnt;                  /* pty read buffer count */
  56.   struct mbuf *sndq;            /* pty send queue */
  57.   int  lastchr;                 /* last chr fetched from send queue */
  58.   int  linelen;                 /* counter for automatic line break */
  59.   char  outbuf[256];            /* pty write buffer */
  60.   char  *outptr;                /* pty write buffer pointer */
  61.   int  outcnt;                  /* pty write buffer count */
  62.   void (*readfnc) __ARGS((void *fncarg));
  63.                 /* func to call if pty is readable */
  64.   void (*closefnc) __ARGS((void *fncarg));
  65.                 /* func to call if pty gets closed */
  66.   void  *fncarg;                /* argument for readfnc and closefnc */
  67.   int  telnet;                  /* telnet mode */
  68.   int  state;                   /* telnet state */
  69.   char  option[NOPTIONS+1];     /* telnet options */
  70. };
  71.  
  72. static char  pty_inuse[256];
  73.  
  74. static int find_pty __ARGS((int *numptr, char *slave));
  75. static void restore_pty __ARGS((char *id));
  76. static void write_log_header __ARGS((int fd, char *user, char *protocol));
  77. static int do_telnet __ARGS((struct login_cb *tp, int chr));
  78. static void write_pty __ARGS((struct login_cb *tp));
  79. static void excp_handler __ARGS((struct login_cb *tp));
  80.  
  81. /*---------------------------------------------------------------------------*/
  82.  
  83. #define pty_name(name, prefix, num) \
  84.   sprintf(name, "%s%c%x", prefix, 'p' + (num >> 4), num & 0xf)
  85.  
  86. /*---------------------------------------------------------------------------*/
  87.  
  88. static int  find_pty(numptr, slave)
  89. int  *numptr;
  90. char  *slave;
  91. {
  92.  
  93.   char  master[80];
  94.   int  fd, num;
  95.  
  96.   for (num = 0; ; num++)
  97.     if (!pty_inuse[num]) {
  98.       pty_name(master, MASTERPREFIX, num);
  99.       if ((fd = open(master, O_RDWR | O_NDELAY, 0600)) >= 0) {
  100.     pty_inuse[num] = 1;
  101.     *numptr = num;
  102.     pty_name(slave, SLAVEPREFIX, num);
  103.     return fd;
  104.       }
  105.       if (errno != EBUSY) return (-1);
  106.       pty_inuse[num] = 1;
  107.     }
  108. }
  109.  
  110. /*---------------------------------------------------------------------------*/
  111.  
  112. static void restore_pty(id)
  113. char  *id;
  114. {
  115.   char  filename[80];
  116.  
  117.   sprintf(filename, "%s%s", MASTERPREFIX, id);
  118.   chown(filename, 0, 0);
  119.   chmod(filename, 0666);
  120.   sprintf(filename, "%s%s", SLAVEPREFIX, id);
  121.   chown(filename, 0, 0);
  122.   chmod(filename, 0666);
  123. }
  124.  
  125. /*---------------------------------------------------------------------------*/
  126.  
  127. void fixutmpfile()
  128. {
  129.   register struct utmp *up;
  130.  
  131.   while (up = getutent())
  132.     if (up->ut_type == USER_PROCESS && kill(up->ut_pid, 0)) {
  133.       restore_pty(up->ut_id);
  134.       up->ut_user[0] = '\0';
  135.       up->ut_type = DEAD_PROCESS;
  136.       up->ut_exit.e_termination = 0;
  137.       up->ut_exit.e_exit = 0;
  138.       up->ut_time = secclock();
  139.       pututline(up);
  140.     }
  141.   endutent();
  142. }
  143.  
  144. /*---------------------------------------------------------------------------*/
  145.  
  146. struct passwd *getpasswdentry(name, create)
  147. char  *name;
  148. int  create;
  149. {
  150.  
  151.   FILE * fp;
  152.   char  *cp;
  153.   char  bitmap[MAXUID+1];
  154.   char  homedir[80];
  155.   char  homedirparent[80];
  156.   char  username[128];
  157.   int  fd;
  158.   int  uid;
  159.   struct passwd *pw;
  160.  
  161.   /* Fix user name */
  162.  
  163.   for (cp = username; isalnum(uchar(*name)); *cp++ = tolower(uchar(*name++))) ;
  164.   *cp = '\0';
  165.   if (!isalpha(uchar(*username)) || strlen(username) > 8)
  166.     strcpy(username, DEFAULTUSER);
  167.  
  168.   /* Search existing passwd entry */
  169.  
  170.   while ((pw = getpwent()) && strcmp(username, pw->pw_name)) ;
  171.   endpwent();
  172.   if (pw) return pw;
  173.   if (!create) return 0;
  174.  
  175.   /* Find free user id */
  176.  
  177.   if ((fd = open(PWLOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  178.   close(fd);
  179.   memset(bitmap, 0, sizeof(bitmap));
  180.   while (pw = getpwent()) {
  181.     if (!strcmp(username, pw->pw_name)) break;
  182.     if (pw->pw_uid <= MAXUID) bitmap[pw->pw_uid] = 1;
  183.   }
  184.   endpwent();
  185.   if (pw) {
  186.     unlink(PWLOCKFILE);
  187.     return pw;
  188.   }
  189.   for (uid = FIRSTUID; uid <= MAXUID && bitmap[uid]; uid++) ;
  190.   if (uid > MAXUID) {
  191.     unlink(PWLOCKFILE);
  192.     return 0;
  193.   }
  194.  
  195.   /* Add user to passwd file */
  196.  
  197.   sprintf(homedirparent, "%s/%.3s...", HOMEDIRPARENTPARENT, username);
  198.   sprintf(homedir, "%s/%s", homedirparent, username);
  199.   if (!(fp = fopen(PASSWDFILE, "a"))) {
  200.     unlink(PWLOCKFILE);
  201.     return 0;
  202.   }
  203.   fprintf(fp, "%s:,./:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  204.   fclose(fp);
  205.   pw = getpwuid(uid);
  206.   endpwent();
  207.   unlink(PWLOCKFILE);
  208.  
  209.   /* Create home directory */
  210.  
  211.   mkdir(homedirparent, 0755);
  212.   mkdir(homedir, 0755);
  213.   chown(homedir, uid, GID);
  214.   return pw;
  215. }
  216.  
  217. /*---------------------------------------------------------------------------*/
  218.  
  219. static void write_log_header(fd, user, protocol)
  220. int  fd;
  221. char  *user, *protocol;
  222. {
  223.  
  224.   char  buf[1024];
  225.   struct tm *tm;
  226.  
  227.   tm = localtime((long *) &Secclock);
  228.   sprintf(buf,
  229.       "%s at %2d-%.3s-%02d %2d:%02d:%02d by %s\n",
  230.       protocol,
  231.       tm->tm_mday,
  232.       "JanFebMarAprMayJunJulAugSepOctNovDec" + 3 * tm->tm_mon,
  233.       tm->tm_year % 100,
  234.       tm->tm_hour,
  235.       tm->tm_min,
  236.       tm->tm_sec,
  237.       user);
  238.   write_log(fd, buf, (int) strlen(buf));
  239. }
  240.  
  241. /*---------------------------------------------------------------------------*/
  242.  
  243. static int  do_telnet(tp, chr)
  244. struct login_cb *tp;
  245. int  chr;
  246. {
  247.   struct termio termio;
  248.  
  249.   switch (tp->state) {
  250.   case TS_DATA:
  251.     if (chr != IAC) {
  252.       /*** if (!tp->option[TN_TRANSMIT_BINARY]) chr &= 0x7f; ***/
  253.       return 1;
  254.     }
  255.     tp->state = TS_IAC;
  256.     break;
  257.   case TS_IAC:
  258.     switch (chr) {
  259.     case WILL:
  260.       tp->state = TS_WILL;
  261.       break;
  262.     case WONT:
  263.       tp->state = TS_WONT;
  264.       break;
  265.     case DO:
  266.       tp->state = TS_DO;
  267.       break;
  268.     case DONT:
  269.       tp->state = TS_DONT;
  270.       break;
  271.     case IAC:
  272.       tp->state = TS_DATA;
  273.       return 1;
  274.     default:
  275.       tp->state = TS_DATA;
  276.       break;
  277.     }
  278.     break;
  279.   case TS_WILL:
  280.     tp->state = TS_DATA;
  281.     break;
  282.   case TS_WONT:
  283.     tp->state = TS_DATA;
  284.     break;
  285.   case TS_DO:
  286.     if (chr <= NOPTIONS) tp->option[chr] = 1;
  287.     if (chr == TN_ECHO) {
  288.       ioctl(tp->pty, TCGETA, &termio);
  289.       termio.c_lflag |= (ECHO | ECHOE);
  290.       ioctl(tp->pty, TCSETA, &termio);
  291.     }
  292.     tp->state = TS_DATA;
  293.     break;
  294.   case TS_DONT:
  295.     if (chr <= NOPTIONS) tp->option[chr] = 0;
  296.     if (chr == TN_ECHO) {
  297.       ioctl(tp->pty, TCGETA, &termio);
  298.       termio.c_lflag &= ~(ECHO | ECHOE);
  299.       ioctl(tp->pty, TCSETA, &termio);
  300.     }
  301.     tp->state = TS_DATA;
  302.     break;
  303.   }
  304.   return 0;
  305. }
  306.  
  307. /*---------------------------------------------------------------------------*/
  308.  
  309. static void write_pty(tp)
  310. struct login_cb *tp;
  311. {
  312.  
  313.   char *p;
  314.   int chr;
  315.   int lastchr;
  316.   int n;
  317.  
  318.   if (!tp->outcnt) {
  319.     p = tp->outbuf;
  320.     while ((chr = PULLCHAR(&tp->sndq)) != -1) {
  321.       lastchr = tp->lastchr;
  322.       tp->lastchr = chr;
  323.       if (!tp->telnet || do_telnet(tp, uchar(chr))) {
  324.     if (lastchr != '\r' || chr != '\0' && chr != '\n') {
  325.       *p++ = chr;
  326.       if (chr == '\r' || chr == '\n') {
  327.         tp->linelen = 0;
  328.         break;
  329.       }
  330.       if (++tp->linelen >= 250) {
  331.         *p++ = '\n';
  332.         tp->linelen = 0;
  333.         break;
  334.       }
  335.     }
  336.       }
  337.     }
  338.     tp->outptr = tp->outbuf;
  339.     tp->outcnt = p - tp->outbuf;
  340.   }
  341.   if (tp->outcnt) {
  342.     n = write(tp->pty, tp->outptr, tp->outcnt);
  343.     if (n < 0) n = 0;
  344.     if (n) write_log(tp->pty, tp->outptr, n);
  345.     tp->outptr += n;
  346.     tp->outcnt -= n;
  347.   }
  348.   if (!tp->outcnt && !tp->sndq) off_write(tp->pty);
  349. }
  350.  
  351. /*---------------------------------------------------------------------------*/
  352.  
  353. static void excp_handler(tp)
  354. struct login_cb *tp;
  355. {
  356.   struct request_info request_info;
  357.  
  358.   if (ioctl(tp->pty, TIOCREQCHECK, &request_info)) return;
  359.   ioctl(tp->pty, TIOCREQSET, &request_info);
  360.   if (request_info.request == TIOCCLOSE) {
  361.     off_read(tp->pty);
  362.     off_write(tp->pty);
  363.     off_excp(tp->pty);
  364.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  365.   }
  366. }
  367.  
  368. /*---------------------------------------------------------------------------*/
  369.  
  370. struct login_cb *login_open(user, protocol, read_upcall, close_upcall, upcall_arg)
  371. char  *user, *protocol;
  372. void (*read_upcall) __ARGS((void *arg));
  373. void (*close_upcall) __ARGS((void *arg));
  374. void  *upcall_arg;
  375. {
  376.  
  377.   char  *env = 0;
  378.   char  slave[80];
  379.   int  i;
  380.   struct login_cb *tp;
  381.   struct passwd *pw;
  382.   struct termio termio;
  383.   struct utmp utmp;
  384.  
  385.   tp = (struct login_cb *) calloc(1, sizeof(struct login_cb ));
  386.   if (!tp) return 0;
  387.   tp->telnet = !strcmp(protocol, "TELNET");
  388.   if ((tp->pty = find_pty(&tp->num, slave)) < 0) {
  389.     free(tp);
  390.     return 0;
  391.   }
  392.   strcpy(tp->id, slave + strlen(slave) - 2);
  393.   tp->readfnc = read_upcall;
  394.   tp->closefnc = close_upcall;
  395.   tp->fncarg = upcall_arg;
  396.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  397.   on_excp(tp->pty, (void (*)()) excp_handler, tp);
  398.   i = 1;
  399.   ioctl(tp->pty, TIOCTRAP, &i);
  400.   write_log_header(tp->pty, user, protocol);
  401.   if (!(tp->pid = fork())) {
  402.     rtprio(0, RTPRIO_RTOFF);
  403.     pw = getpasswdentry(user, 1);
  404.     if (!pw || pw->pw_passwd[0]) pw = getpasswdentry("", 0);
  405.     for (i = 0; i < _NFILE; i++) close(i);
  406.     setpgrp();
  407.     open(slave, O_RDWR, 0666);
  408.     dup(0);
  409.     dup(0);
  410.     chmod(slave, 0622);
  411.     memset(&termio, 0, sizeof(termio));
  412.     termio.c_iflag = ICRNL | IXOFF;
  413.     termio.c_oflag = OPOST | ONLCR | TAB3;
  414.     termio.c_cflag = B1200 | CS8 | CREAD | CLOCAL;
  415.     termio.c_lflag = ISIG | ICANON;
  416.     termio.c_cc[VINTR]  = 127;
  417.     termio.c_cc[VQUIT]  =  28;
  418.     termio.c_cc[VERASE] =   8;
  419.     termio.c_cc[VKILL]  =  24;
  420.     termio.c_cc[VEOF]   =   4;
  421.     ioctl(0, TCSETA, &termio);
  422.     ioctl(0, TCFLSH, 2);
  423.     if (!pw || pw->pw_passwd[0]) exit(1);
  424.     memset(&utmp, 0, sizeof(utmp));
  425.     strcpy(utmp.ut_user, "LOGIN");
  426.     strcpy(utmp.ut_id, tp->id);
  427.     strcpy(utmp.ut_line, slave + 5);
  428.     utmp.ut_pid = getpid();
  429.     utmp.ut_type = LOGIN_PROCESS;
  430.     utmp.ut_time = secclock();
  431. #ifdef _UTMP_INCLUDED   /* for HP-UX 6.5 compatibility */
  432.     strncpy(utmp.ut_host, protocol, sizeof(utmp.ut_host));
  433. #endif
  434.     pututline(&utmp);
  435.     endutent();
  436.     execle("/bin/login", "login", pw->pw_name, (char *) 0, &env);
  437.     exit(1);
  438.   }
  439.   return tp;
  440. }
  441.  
  442. /*---------------------------------------------------------------------------*/
  443.  
  444. void login_close(tp)
  445. struct login_cb *tp;
  446. {
  447.  
  448.   int  fwtmp;
  449.   struct utmp utmp, *up;
  450.  
  451.   if (!tp) return;
  452.   if (tp->pty > 0) {
  453.     off_read(tp->pty);
  454.     off_write(tp->pty);
  455.     off_excp(tp->pty);
  456.     close(tp->pty);
  457.     restore_pty(tp->id);
  458.     pty_inuse[tp->num] = 0;
  459.     write_log(tp->pty, (char *) 0, -1);
  460.   }
  461.   if (tp->pid > 0) {
  462.     kill(-tp->pid, SIGHUP);
  463.     memset(&utmp, 0, sizeof(utmp));
  464.     strcpy(utmp.ut_id, tp->id);
  465.     utmp.ut_type = DEAD_PROCESS;
  466.     if (up = getutid(&utmp)) {
  467.       up->ut_user[0] = '\0';
  468.       up->ut_type = DEAD_PROCESS;
  469.       up->ut_exit.e_termination = 0;
  470.       up->ut_exit.e_exit = 0;
  471.       up->ut_time = secclock();
  472.       memcpy(&utmp, up, sizeof(utmp));
  473.       pututline(up);
  474.       fwtmp = open("/etc/wtmp", O_WRONLY | O_CREAT | O_APPEND, 0644);
  475.       write(fwtmp, (char *) &utmp, sizeof(utmp));
  476.       close(fwtmp);
  477.     }
  478.     endutent();
  479.   }
  480.   free_q(&tp->sndq);
  481.   free(tp);
  482. }
  483.  
  484. /*---------------------------------------------------------------------------*/
  485.  
  486. #define ASIZE 512
  487.  
  488. #define add_to_mbuf(chr) \
  489. { \
  490.   if (!head) head = tail = alloc_mbuf(ASIZE); \
  491.   if (tail->cnt >= ASIZE) tail = tail->next = alloc_mbuf(ASIZE); \
  492.   tail->data[tail->cnt++] = chr; \
  493.   cnt--; \
  494. }
  495.  
  496. /*---------------------------------------------------------------------------*/
  497.  
  498. struct mbuf *login_read(tp, cnt)
  499. struct login_cb *tp;
  500. int  cnt;
  501. {
  502.  
  503.   int  chr;
  504.   struct mbuf *head, *tail;
  505.  
  506.   if (cnt <= 0) {
  507.     off_read(tp->pty);
  508.     return 0;
  509.   }
  510.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  511.   head = 0;
  512.   while (cnt) {
  513.     if (tp->inpcnt <= 0) {
  514.       if ((tp->inpcnt = read(tp->pty, tp->inpptr = tp->inpbuf, sizeof(tp->inpbuf))) <= 0)
  515.     return head;
  516.       write_log(tp->pty, tp->inpbuf, tp->inpcnt);
  517.     }
  518.     tp->inpcnt--;
  519.     chr = uchar(*tp->inpptr++);
  520.     if (chr == 0x11 || chr == 0x13) {
  521.       /* ignore XON / XOFF */
  522.     } else if (tp->telnet) {
  523.       add_to_mbuf(chr);
  524.       if (chr == IAC) add_to_mbuf(IAC);
  525.     } else {
  526.       if (chr != '\n') add_to_mbuf(chr);
  527.     }
  528.   }
  529.   return head;
  530. }
  531.  
  532. /*---------------------------------------------------------------------------*/
  533.  
  534. void login_write(tp, bp)
  535. struct login_cb *tp;
  536. struct mbuf *bp;
  537. {
  538.   append(&tp->sndq, bp);
  539.   on_write(tp->pty, (void (*)()) write_pty, tp);
  540.   if (tp->linelen) write_pty(tp);
  541. }
  542.  
  543.